package cn.amos.mvc.common.ip;

import com.alibaba.fastjson.JSON;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * PROJECT: gateway
 * DESCRIPTION: note
 *
 * @author Daoyuan
 * @date 2019/1/18
 */
@RestController
@RequestMapping("partner/back")
public class BackConfigController {

    private static final String IP_REGEX = "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$";
    private static final Logger LOGGER = LoggerFactory.getLogger(BackConfigController.class);

    /**
     * single session
     */
    private static volatile Session session;

    @RequestMapping(value = "hello/{ip:.+}", method = RequestMethod.GET)
    public String ip(@PathVariable("ip") String ip) {
        System.out.println("input ip is " + ip);
        return ip;
    }

    @RequestMapping(value = "white/{ip:.+}", method = RequestMethod.GET)
    public String addBackWhiteIp(@PathVariable("ip") String ip) {
        if (formatError(ip)) {
            LOGGER.error(">>>>>>>>> IP [{}] 格式错误", ip);
            return "失败";
        }
        ServerMessageVO serverMessageVO = JSON.parseObject("{\"host\":\"47.99.90.112\",\"password\":\"e)A}9]<cL/&tmaU\",\"port\":22,\"user\":\"root\"}", ServerMessageVO.class);

        return addWhiteIp(ip, serverMessageVO);
    }

    private static String addWhiteIp(String ip, ServerMessageVO serverMessageVO) {
        String cmdExistIp = "cat /etc/nginx/block_ip.txt";
        String cmdAddIp = "./white_ip.sh " + ip;
        AtomicBoolean ipExist = new AtomicBoolean(false);
        try {
            long begin = System.currentTimeMillis();
            Session session = getInstance(serverMessageVO.getHost(), serverMessageVO.getUser(), serverMessageVO.getPassword(), serverMessageVO.getPort());
            LOGGER.info(">>>>>>>>> 连接 [{}] 成功. [耗时 {} 毫秒]", serverMessageVO.getHost(), (System.currentTimeMillis() - begin));

            // 遍历执行结果, IP 不能重复添加
            List<String> execResult = execCmd(session, cmdExistIp);
            execResult.forEach(str -> {
                if (str.contains(ip)) {
                    ipExist.set(true);
                }
            });
            if (ipExist.get()) {
                return MessageFormat.format("IP [{0}] 已存在,请勿重复添加", ip);
            }

            String addIpResult = JSON.toJSONString(execCmd(session, cmdAddIp));
            LOGGER.info(">>>>>>>>> 添加 IP 执行结果: {}", addIpResult);
            return addIpResult;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeSession();
        }
        return "未知错误";
    }

    /**
     * 初始化 Session
     */
    private static Session getInstance(String host, String name, String password, int port) throws JSchException {
        if (session != null) {
            return session;
        }

        JSch jsch = new JSch();
        session = jsch.getSession(name, host, port);
        session.setPassword(password);
        session.setConfig("StrictHostKeyChecking", "no");
        session.connect();

        return session;
    }

    /**
     * 执行命令
     */
    private static List<String> execCmd(Session session, String cmd) throws JSchException, IOException {
        long begin = System.currentTimeMillis();
        LOGGER.info(">>>>>>>>> 执行命令 {} 开始...", cmd);
        List<String> callback = new ArrayList<>();
        ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
        channelExec.setCommand(cmd);
        channelExec.setInputStream(null);
        channelExec.setErrStream(System.err);
        channelExec.connect();
        InputStream inputStream = channelExec.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String buf;
        while ((buf = reader.readLine()) != null) {
            callback.add(buf);
        }
        reader.close();
        channelExec.disconnect();
        LOGGER.info(">>>>>>>>> 执行命令 {} 完成. >>> [耗时 {} 毫秒]", cmd, (System.currentTimeMillis() - begin));

        return callback;
    }

    /**
     * 关闭 Session
     */
    private static void closeSession() {
        if (session != null) {
            session.disconnect();
            session = null;
        }
    }

    /**
     * 校验 IP 格式
     *
     * @param ip IP 地址
     * @return true 格式正确；false：格式错误。
     */
    private static boolean formatError(String ip) {
        if (StringUtils.isBlank(ip)) {
            return true;
        }
        Matcher matcher = Pattern.compile(IP_REGEX).matcher(ip);
        if (matcher.matches()) {
            String[] split = ip.split("\\.");
            for (String str : split) {
                if (Integer.valueOf(str) > 255) {
                    return true;
                }
            }
            return false;
        }
        return true;
    }

}
